iT邦幫忙

1

【Flutter】flutter doctor --android-licenses 出問題?Android SDK Command-line Tools 23 的坑與解法

  • 分享至 

  • xImage
  •  

如果你最近更新了 Android SDK,然後發現 flutter doctor --android-licenses 只吐出幾行警告就結束,該出現的授權提示一個也沒有,這篇是為你準備的。


問題

執行 flutter doctor --android-licenses,畫面只吐出兩段警告就結束了,完全沒有出現以往那個「Review licenses that have not been accepted (y/N)?」的互動提示:

flutter doctor --android-licenses 只印出警告就結束

WARNING: The SDK Manager CLI tool (sdkmanager) is deprecated. Android CLI will be used instead.
The 'android' binary can also be found in the cmdline-tools directory, and 'android sdk' is the replacement for 'sdkmanager'.
To learn more about the Android CLI and how to use it, see the documentation (https://d.android.com/tools/agents/android-cli)

Warning: The --licenses option is no longer needed.

flutter doctor 則會一直卡在這個狀態:

[!] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
    X Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.

叫你去跑一個跑了也沒用的指令,無限迴圈。

原因

Google 在新版的 Android SDK Command-line Tools 裡棄用了 sdkmanager,改推新的 android CLI。棄用從 22.0 就開始,但那時 sdkmanager 還是自己做事,--licenses 完全正常。

到了 23.0sdkmanager 被改寫成一層轉譯腳本:它把舊旗標翻譯成 android sdk 的子指令再轉呼叫過去,--list 譯成 list --all--update 譯成 update--uninstall 譯成 remove。而 --licenses 沒有任何子指令可以對應,於是只回你一句 The --licenses option is no longer needed. 就結束。

Flutter 的 flutter doctor --android-licenses 底層正是去跑 sdkmanager --licenses,於是互動式的授權同意提示再也不會出現。

對應的 issue 是 flutter/flutter#191487

--licenses 是選項(旗標),不是子指令。分辨方式很直接:以 --- 開頭的是選項,例如 --licenses-h--sdk=PARAM;不帶橫線的裸字才是子指令,例如 android sdk 裡的 sdk。所以 sdkmanager --licenses 的結構是「執行檔 + 選項」,而 android sdk install 的結構是「執行檔 + 子指令 + 子指令」。


解法:把 Command-line Tools 降版到 22.0

  1. 開啟 Android Studio。
  2. 開啟 SDK ManagerLanguages & Frameworks > Android SDK)。
  3. 選擇 SDK Tools 分頁。
  4. 勾選右下角的 Show Package Details
  5. 展開 Android SDK Command-line Tools
  6. 取消勾選 23.0 版(或你目前安裝的最新版),改勾選 22.0 版。
  7. Apply 完成降版。

Android Studio SDK Manager 中降版 Command-line Tools

  1. 重新開啟 PowerShell,先確認 latest 資料夾真的消失了:
dir $env:LOCALAPPDATA\Android\Sdk\cmdline-tools

清單裡應該只剩下 22.0。這一步不能跳過,因為 Flutter 找 sdkmanager 時會優先使用 cmdline-tools\latest\bin\,找不到才退而挑版號最高的目錄。所以只要 latest 還在、裡面裝的又是 23.0,那你裝了 22.0 也等於白裝。

  1. 執行:
flutter doctor --android-licenses

熟悉的授權提示就回來了,一路 y 按到底即可:

降版後互動式授權提示正常出現

6 of 7 SDK package licenses not accepted.
Review licenses that have not been accepted (y/N)? y

1/6: License android-googletv-license:

全部接受完之後再跑一次 flutter doctor,Android toolchain 就會變成綠色打勾了。


那 Flutter 官方修了嗎?

修了一半,而且還沒送到你手上。

修正(PR #191554)的做法是:當 Flutter 偵測到 --licenses option is no longer needed 這句話時,改成去看 <sdk>/licenses/ 目錄底下有沒有非空的授權檔案,只要有任何一個就視為授權已接受,繞過已經失效的 sdkmanager 輸出解析。

這個修正已經進了 master 和 beta,現行 stable 3.47.2 還沒有(本文查證日期為 2026-09-08)。所以如果你在網路上看到「3.48.0 已經修好了」,那指的是 beta 版號,不是你能用的正式版。

不過不必等到下一個大版本。Flutter 的 stable 次版號每三個週期才跳一次(3.41 → 3.44 → 3.47,下一個是 3.50),照正常節奏這個修正得等到 3.50。但 PR #191554 掛了 cp: betacp: stable 兩個 cherry-pick 標籤,而且兩邊都已經生效。stable 這邊走 PR #192133,2026-09-03 併進了 flutter-3.47-candidate.0,該分支的 CHANGELOG 也已經寫好 3.47.3 的條目,明列 issue #191487。

也就是說,修正會隨 stable 3.47.3 這個 hotfix 出貨,但要注意它修的是「判讀」而不是「接受」。PR #191554 只動了偵測授權狀態的那段程式碼,負責實際接受授權的 runLicenseManager() 一行都沒改,在 23.0 底下 flutter doctor --android-licenses 依然什麼都不做。所以 3.47.3 只能讓本來就接受過授權的人變回綠燈;如果你是全新環境、licenses 目錄還是空的,升級之後照樣卡住,還是得降版。


順便吐槽一下

平心而論,Flutter 這邊反應算快,issue 開沒幾天 PR 就 merge 進 master 了。真正讓人火大的是上游。

第一,這是一個假裝成功的失敗。 Flutter 有兩條路都踩到這顆地雷。flutter doctor --android-licenses 走的是 runLicenseManager(),它直接執行 sdkmanager --licenses,把你的輸入原封不動轉給它,然後只看 exit code;普通的 flutter doctor 走的是 licensesAccepted,另外跑一次同樣的指令並解析輸出。

而 23.0 的 sdkmanager --licenses 只會印兩段警告、什麼都不做,然後回傳 exit code 0。這不是推測,sdkmanager.bat 裡就是這樣寫的:

if "%ARG%"=="--licenses" (
    echo Warning: The --licenses option is no longer needed.>&2
    set LICENSES_CONFIGURED=true
    ...
)
...
if "!SPECIAL_CMD!"=="" if "!PACKAGES!"=="" (
    if "!LICENSES_CONFIGURED!"=="true" exit /b 0

於是 flutter doctor --android-licenses 拿到 0 就判定成功,而 flutter doctor 的三個正則全部比對不到,只能回報「狀態未知」。

它從頭到尾沒說過「成功」兩個字,但對腳本來說,exit code 0 就是成功;對你來說,畫面上就只是幾行看起來無關痛癢的警告。

而在 Flutter 專案裡,這個迴圈會漂亮地閉合起來。Flutter 的 gradle_errors.dart 有一個 licenseNotAcceptedHandler,專門攔截建置時出現的 You have not accepted the license agreements...,把訊息改寫成:

To resolve this, please run the following command in a Terminal:
flutter doctor --android-licenses

於是當你的 build 因為授權未接受而失敗時,Flutter 會明確地把你導向 flutter doctor --android-licenses,回到原點。

一個直接壞掉、回傳非 0 的指令,都比一個安靜地什麼都不做卻回傳 0 的指令好。

第二,新 CLI 根本沒有接手這個功能。 官方說 android sdksdkmanager 的替代品,那我們實際跑一次 android sdk -h 看看它提供哪些子指令:

Commands:
  install  Install SDK packages
  update   Update one or all packages to the latest version
  remove   Remove packages from the SDK
  list     List installed and available SDK packages

android sdk -h 的子指令只有四個

installupdateremovelist。沒了。沒有 licenses、沒有 --accept-licenses,Android CLI 的官方文件裡也找不到任何一個管理授權的指令。所謂的「替代品」,替代掉的是「你能夠明確看見並同意授權條款」這件事本身。授權該怎麼查、怎麼接受,新 CLI 一句話都沒交代,整件事變成一個黑箱。

第三,授權這塊完全沒有遷移指引。 官方在 sdkmanager 的文件頁掛了一句棄用聲明,要你改用 android sdk,還附了連結(只有英文版有這句,中文版至今沒翻譯過來,讀中文文件的人根本不會知道它被棄用了)。但那個連結點過去,就是上面那四個子指令的用法,授權隻字未提。而同一頁的「接受授權」章節到今天還寫著:

If you don't have Android Studio installed, or it's for a CI server or other headless Linux device without a GUI installed, do the following from the command line:

sdkmanager --licenses

那頁最後更新於 2026-09-02(UTC)。也就是說,官方一邊宣告這個工具棄用,一邊繼續教你用它去做一件它在 latest 版本上已經做不到的事。

至於變更紀錄,Command-line Tools 的官方 release notes 停在 2020 年 12 月的 5.0,之後一路到 23.0 一個字都沒補。本文那套降版步驟,出自 Flutter issue 底下一位使用者的留言。

棄用一個功能之前先提供替代品,這不是什麼高標準,這是基本禮貌。Google 這次給了過渡期,卻沒在過渡期裡把替代品做出來:22.0 警告了一整版,23.0 直接動手,而 android sdk 到今天依然沒有任何授權指令。

第四,Command-line Tools 把這個破壞性變更裝進了一個叫做 latest 的目錄。 SDK Manager 裡那個不帶版號的 Android SDK Command-line Tools (latest) 會裝進 cmdline-tools/latest/,而它現在指向的就是 23.0(勾選特定版號安裝時才會裝進 cmdline-tools/<版號>/)。

問題是,latest 這個目錄名被很多工具當成固定常數在用。Flutter 找 sdkmanager 時第一個就去看 cmdline-tools/latest/bin/;GitHub Actions 的 runner image 也一樣,不管下載回來的是哪一版,一律搬進 cmdline-tools/latest,再把 sdkmanager 的路徑寫死在那裡。

而 SDK Manager 裡那個不帶版號的選項,裝的永遠是這個固定路徑,至於裡面放哪一版則由 Google 決定。所以你在 Android Studio 勾的其實不是某個版本,而是「Google 當下指向的那一版」。今天勾就拿到 23.0;等 Google 把 latest 換成 24.0,你下次更新拿到的就是 24.0。

要在一個這麼多工具都預設指向的路徑上發布破壞性變更,那你至少要確保新版本能做到舊版本做得到的事。


參考連結


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言